package com.huabo.file;

import com.huabo.file.ftp.FTPClientConfigure;
import com.huabo.file.ftp.FTPClientFactory;
import com.huabo.file.ftp.FTPClientPool;
import com.huabo.utils.KeyUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;

import java.io.*;
import java.util.*;

import static java.lang.System.in;

/**
 * ftp协议保存文件
 * Created by Jackie Liu on 2017/4/23.
 */
public class FtpFileOperation implements FileOperation, InitializingBean {

    private static final Logger logger = LoggerFactory.getLogger(FtpFileOperation.class);

    private FTPClientConfigure configure;//ftp配置,依赖注入
    private FTPClientPool pool;//ftp对象池
    private String saveFilePath;//ftp保存文件的路径,依赖注入
    private Map<String, Integer> fileMap = new HashMap<>();

    @Override
    public String save(File file) throws FileNotFoundException {
        if (file == null || !file.exists()) {
            throw new FileNotFoundException();
        }
        InputStream in = new FileInputStream(file);
        String logicName = KeyUtils.getKey() + "." + FilenameUtils.getExtension(file.getName());
        return save(in, logicName);
    }

    @Override
    public String save(InputStream is, String logicName) {
        FTPClient ftpClient = getClient();
        //String path = saveFilePath + logicName;
        String path = weightPolling() + logicName;
        try {
            //ftpClient.changeWorkingDirectory(saveFilePath);
            ftpClient.storeFile(path, is);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    logger.error("", e);
                }
            }
            returnClient(ftpClient);
        }
        return path;
    }

    @Override
    public byte[] read(String filePath) {
        FTPClient client = getClient();
        InputStream is = null;
        try {
            // Download file.
            //String name = KeyUtils.getKey() + "." + FilenameUtils.getExtension(filePath);
            is = client.retrieveFileStream(filePath);
            if (is == null) {
                throw new IOException("Error loading file " + filePath + " from FTP server. Check FTP permissions and path.");
            }
            return toByteArray(is);
        } catch (IOException e) {
            logger.error("", e);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException ex) {
                    logger.error("", ex);
                }
            }
            try {
                client.completePendingCommand();
            } catch (IOException e) {
                logger.error("", e);
            }
            returnClient(client);
        }
        return null;
    }

    @Override
    public boolean remove(String filePath) {
        if (StringUtils.isEmpty(filePath)) {
            return false;
        }
        FTPClient client = getClient();
        try {
            client.deleteFile(filePath);
        } catch (IOException e) {
            logger.error("", e);
            return false;
        } finally {
            returnClient(client);
        }
        return true;
    }

    private byte[] toByteArray(InputStream is) throws IOException {
        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        byte[] buff = new byte[100];
        int rc = 0;
        while ((rc = is.read(buff, 0, 100)) > 0) {
            swapStream.write(buff, 0, rc);
        }
        return swapStream.toByteArray();
    }

    /**
     * 创建多级目录
     */
    private void mkdir() {
        FTPClient client = null;
        try {
            if (StringUtils.isEmpty(saveFilePath)) {
                return;
            }
            StringTokenizer s = new StringTokenizer(saveFilePath + "temp", "/");
            s.countTokens();
            String pathName = "";
            client = getClient();
            while (s.hasMoreElements()) {
                pathName = pathName + "/" + (String) s.nextElement();
                try {
                    int size = client.listFiles(pathName).length;
                    if (size <= 0) {
                        client.mkd(pathName);
                    }
                } catch (IOException e) {
                    logger.error(String.format("ftp文件夹创建失败，路径为：%s", pathName), e);
                }
            }

            pathName =  pathName.replace("temp", "");

            for (int i = 10; i < 30; i++) {
                String path = pathName + String.valueOf(i);
                int size = client.listFiles(path).length;
                if (size <= 0) {
                    client.mkd(path);
                }
                fileMap.put(path + "/", 1);
            }
        } catch (Exception e) {
            logger.error("", e);
        } finally {
            returnClient(client);
        }
    }

    /**
     * 从对象池中获取FTPClient实例
     *
     * @return
     */
    private FTPClient getClient() {
        if (pool == null) {
            throw new RuntimeException("FTPClientPool实例不存在或者初始化失败.....");
        }
        try {
            return pool.borrowObject();
        } catch (Exception e) {
            logger.error("", e);
        }
        return null;
    }

    /**
     * 使用过的FtpClient实例返回给对象池
     *
     * @param client
     */
    private void returnClient(FTPClient client) {
        try {
            pool.returnObject(client);
        } catch (Exception e) {
            logger.error("", e);
        }
    }

    @Override
    public void afterPropertiesSet() {
        FTPClientFactory factory = new FTPClientFactory(configure);
        try {
            pool = new FTPClientPool(factory);
            mkdir();
        } catch (Exception e) {
            logger.error("", e);
        }
    }

    public void close() {
        if (pool != null) {
            try {
                pool.close();
            } catch (Exception e) {
                logger.error("", e);
            }
        }
    }

    public FTPClientConfigure getConfigure() {
        return configure;
    }

    public void setConfigure(FTPClientConfigure configure) {
        this.configure = configure;
    }

    public String getSaveFilePath() {
        return saveFilePath;
    }

    public void setSaveFilePath(String saveFilePath) {
        if (saveFilePath != null &&
                !saveFilePath.endsWith("/") && !saveFilePath.endsWith("\\")) {
            this.saveFilePath = saveFilePath + "/";
            return;
        }
        this.saveFilePath = saveFilePath;
    }

    public String weightPolling() {
        Map<String, Integer> pollFileMap = new HashMap<String, Integer>();
        pollFileMap.putAll(fileMap);
        Set<String> keySet = pollFileMap.keySet();
        Iterator<String> it = keySet.iterator();
        List<String> serverList = new ArrayList<String>();
        while (it.hasNext()) {
            String server = it.next();
            Integer weight = pollFileMap.get(server);
            for (int i = 0; i < weight; i++) {
                serverList.add(server);
            }
        }
        Random random = new Random();
        int randomPos = random.nextInt(serverList.size());
        String filePath = serverList.get(randomPos);
        return filePath;
    }
}
